package app

import (
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"sync"
	"time"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/dialog"
	"fyne.io/fyne/v2/layout"
	"fyne.io/fyne/v2/widget"
	"github.com/jmoiron/sqlx"
)

// 定义二维数组，用于实时更新任务管理表格的数据
var taskResult []BackupTask

// 定义二维数组，用于实时更新备份记录表格的数据
var backupResult []BackupRecord

// 定义一个变量，用于存储实时更新的选中行(任务管理表格)
var currentSelectedRow BackupTask

// 定义一个变量，用于存储实时更新的选中行(备份记录表格)
//var currentSelectedBackup BackupRecord

// 定义一个空切片，用于存储定时更新的任务列表
var checkBoxList []string

// 定义一个变量，用于存储选中的复选框组
var selectedCheckBox []string

// 创建任务管理表格
func createTaskTable() *widget.Table {
	// 创建一个表格用于显示任务列表
	taskTable := widget.NewTable(
		func() (int, int) { return len(taskResult), 6 },         // 设置表格的行数和列数
		func() fyne.CanvasObject { return widget.NewLabel("") }, // 设置表格的单元格内容
		updateTaskTable, // 更新表格内容的回调函数
	)

	// 启用表头行
	taskTable.ShowHeaderRow = true

	// 自定义表头内容的创建
	taskTable.CreateHeader = func() fyne.CanvasObject {
		return widget.NewLabel("Header Template")
	}

	// 更新自定义表头内容
	taskTable.UpdateHeader = func(id widget.TableCellID, template fyne.CanvasObject) {
		// 根据列索引设置表头标签的文本内容
		switch id.Col {
		case 0:
			template.(*widget.Label).SetText("任务ID")
		case 1:
			template.(*widget.Label).SetText("任务名称")
		case 2:
			template.(*widget.Label).SetText("保留数量")
		case 3:
			template.(*widget.Label).SetText("是否压缩")
		case 4:
			template.(*widget.Label).SetText("目标路径")
		case 5:
			template.(*widget.Label).SetText("备份路径")
		}
	}

	// 设置任务ID列的宽度
	taskTable.SetColumnWidth(0, 100)

	// 设置任务名称列的宽度
	taskTable.SetColumnWidth(1, 200)

	// 设置保留数量列的宽度
	taskTable.SetColumnWidth(2, 100)

	// 设置是否压缩列的宽度
	taskTable.SetColumnWidth(3, 100)

	// 设置目标路径列的宽度
	taskTable.SetColumnWidth(4, 500)

	// 设置备份路径列的宽度
	taskTable.SetColumnWidth(5, 500)

	// 设置表格鼠标点击事件
	taskTable.OnSelected = func(id widget.TableCellID) {
		// 检查是否在表头行上点击
		if id.Row == -1 {
			return
		}

		// 检查是否在有效的行上点击
		if id.Row >= len(taskResult) {
			appLog.Errorf("无效的行索引: %d", id.Row)
			return
		}

		// 获取选中的任务
		currentSelectedRow = taskResult[id.Row]
	}

	return taskTable // 返回任务管理表格
}

// 更新任务管理表格的数据源
func updateTaskData(keyword string) error {
	// 如果关键字为空，则查询所有任务
	if keyword == "" {
		// 构造查询SQL语句
		querySQL := "SELECT task_id, task_name, retention_count, is_compressed, target_directory, backup_directory FROM backup_tasks"

		// 查询数据库中的任务信息
		if err := DB.Select(&taskResult, querySQL); err != nil {
			appLog.Errorf("查询任务失败: %v", err)
			return err
		}

		return nil
	}

	// 如果关键字不为空，则查询包含关键字的任务
	querySQL := "SELECT task_id, task_name, retention_count, is_compressed, target_directory, backup_directory FROM backup_tasks WHERE task_name LIKE ?"

	// 拼接通配符
	searchPattern := fmt.Sprintf("%%%s%%", keyword)

	// 查询数据库中的任务信息
	if err := DB.Select(&taskResult, querySQL, searchPattern); err != nil {
		appLog.Errorf("查询任务失败: %v", err)
		return err
	}

	return nil
}

// 将数据源中的数据更新到表格中
func updateTaskTable(tabId widget.TableCellID, cell fyne.CanvasObject) {
	// 检查行索引是否在有效范围内
	if tabId.Row >= len(taskResult) {
		cell.(*widget.Label).SetText("")
		appLog.Warnf("无效的行索引: %d", tabId.Row)
		return
	}

	// 获取单元格的标签
	label := cell.(*widget.Label)

	// 根据行和列设置标签的文本内容
	if tabId.Row < len(taskResult) {
		// 根据行索引获取对应的任务
		task := taskResult[tabId.Row]

		// 根据列索引设置标签的文本内容
		switch tabId.Col {
		case 0: // 任务ID列
			label.SetText(task.TaskID)
		case 1: // 任务名称列
			label.SetText(task.TaskName)
		case 2: // 保留数量列
			label.SetText(fmt.Sprintf("%d", task.RetentionCount))
		case 3: // 是否压缩列
			label.SetText(fmt.Sprintf("%t", task.IsCompressed))
		case 4: // 目标路径列
			label.SetText(task.TargetDirectory)
		case 5: // 备份路径列
			label.SetText(task.BackupDirectory)
		default:
			label.SetText("") // 如果超出列范围，设置为空字符串
		}
	} else {
		label.SetText("") // 如果超出行范围，设置为空字符串
	}
}

// 新增任务按钮
func addTaskButton(windows fyne.Window) *widget.Button {
	// 创建新增任务按钮
	addTaskButton := widget.NewButton("新增任务", func() {
		// 创建表单项目
		nameItem := widget.NewFormItem("任务名称", widget.NewEntry())                                 // 创建任务名称输入框
		retentionCountItem := widget.NewFormItem("保留数量", widget.NewEntry())                       // 创建保留数量输入框
		isCompressedItem := widget.NewFormItem("是否压缩", widget.NewSelect([]string{"是", "否"}, nil)) // 创建是否压缩下拉框
		targetDirectoryItem := widget.NewFormItem("目标路径", widget.NewEntry())                      // 创建目标路径输入框
		backupDirectoryItem := widget.NewFormItem("备份路径", widget.NewEntry())                      // 创建备份路径输入框

		// 为目标路径添加文件夹选择按钮
		targetDirectoryButton := widget.NewButton("浏览", func() {
			// 创建文件夹选择对话框
			folderDialog := dialog.NewFolderOpen(func(dir fyne.ListableURI, err error) {
				if err != nil {
					appLog.Errorf("文件夹选择对话框错误: %v", err)
					dialog.ShowError(err, windows)
					return
				}
				if dir != nil {
					targetDirectoryItem.Widget.(*widget.Entry).SetText(dir.Path()) // 设置目标路径
				}
			}, windows)

			// 设置对话框的大小
			folderDialog.Resize(fyne.NewSize(600, 500))

			// 显示文件夹选择对话框
			folderDialog.Show()
		})

		// 为备份路径添加文件夹选择按钮
		backupDirectoryButton := widget.NewButton("浏览", func() {
			// 创建文件夹选择对话框
			folderDialog := dialog.NewFolderOpen(func(dir fyne.ListableURI, err error) {
				if err != nil {
					appLog.Errorf("文件夹选择对话框错误: %v", err)
					dialog.ShowError(err, windows)
					return
				}
				if dir != nil {
					backupDirectoryItem.Widget.(*widget.Entry).SetText(dir.Path()) // 设置备份路径
				}
			}, windows)

			// 设置对话框的大小
			folderDialog.Resize(fyne.NewSize(700, 600))

			// 显示文件夹选择对话框
			folderDialog.Show()
		})

		// 创建表单对话框
		formItems := []*widget.FormItem{
			nameItem,           // 任务名称
			retentionCountItem, // 保留数量
			isCompressedItem,   // 是否压缩
			widget.NewFormItem("目标路径", container.New(layout.NewGridLayout(2), targetDirectoryItem.Widget, targetDirectoryButton)), // 目标路径
			widget.NewFormItem("备份路径", container.New(layout.NewGridLayout(2), backupDirectoryItem.Widget, backupDirectoryButton)), // 备份路径
		}

		// 显示表单对话框
		formDialog := dialog.NewForm("新增任务", "提交", "取消", formItems, func(submitted bool) {
			if submitted {
				taskName := nameItem.Widget.(*widget.Entry).Text                         // 获取任务名称的值
				retentionCount := retentionCountItem.Widget.(*widget.Entry).Text         // 获取保留数量的值
				isCompressed := isCompressedItem.Widget.(*widget.Select).Selected == "是" // 获取是否压缩的值
				targetDirectory := targetDirectoryItem.Widget.(*widget.Entry).Text       // 获取目标路径的值
				backupDirectory := backupDirectoryItem.Widget.(*widget.Entry).Text       // 获取备份路径的值

				if taskName == "" {
					dialog.ShowError(fmt.Errorf("任务名称不能为空"), windows)
					appLog.Error("任务名称不能为空")
					return
				}

				if retentionCount == "" {
					dialog.ShowError(fmt.Errorf("保留数量不能为空"), windows)
					appLog.Error("保留数量不能为空")
					return
				}

				if targetDirectory == "" {
					dialog.ShowError(fmt.Errorf("目标路径不能为空"), windows)
					appLog.Error("目标路径不能为空")
					return
				}

				if backupDirectory == "" {
					dialog.ShowError(fmt.Errorf("备份路径不能为空"), windows)
					appLog.Error("备份路径不能为空")
					return
				}

				// 构造备份目录, 格式为: 目标目录_bakup
				backupDirectory = filepath.Join(backupDirectory, fmt.Sprint(filepath.Base(targetDirectory), "_backup"))

				// 插入任务数据
				addTaskSql := "INSERT INTO backup_tasks (task_name, retention_count, is_compressed, target_directory, backup_directory) VALUES (?, ?, ?, ?, ?)"
				if _, err := DB.Exec(addTaskSql, taskName, retentionCount, isCompressed, targetDirectory, backupDirectory); err != nil {
					appLog.Errorf("插入任务数据失败: %v", err)
					dialog.ShowError(fmt.Errorf("保存任务失败: %v", err), windows)
				} else {
					dialog.ShowInformation("提示", "保存任务成功", windows)
					appLog.Successf("保存%s成功", taskName)
				}
			} else {
				appLog.Info("取消新增任务")
			}
		}, windows)

		// 设置表单对话框的尺寸
		formDialog.Resize(fyne.NewSize(400, 300))

		// 显示表单对话框
		formDialog.Show()
	})

	return addTaskButton
}

// 删除任务按钮
/*
删除逻辑:
1、删除备份任务
2、删除备份记录
3、删除备份存放目录
*/
func deleteTaskFunc(windows fyne.Window) {
	// 弹出确认对话框
	confirmDialog := dialog.NewConfirm("确认删除", fmt.Sprintf("确认要删除%s吗?", currentSelectedRow.TaskName), func(confirmed bool) {
		// 用户点击确认按钮
		if confirmed {
			// 构建删除任务的SQL语句
			deleteTaskSql := "DELETE FROM backup_tasks WHERE task_id = ?"
			// 执行删除任务的SQL语句
			if _, err := DB.Exec(deleteTaskSql, currentSelectedRow.TaskID); err != nil {
				appLog.Errorf("删除任务失败: %v", err)
				dialog.ShowError(fmt.Errorf("删除任务失败: %v", err), windows)
				return
			}

			// 构建删除备份记录的SQL语句
			deleteBackupRecordSql := "DELETE FROM backup_records WHERE task_id = ?"
			// 执行删除备份记录的SQL语句
			if _, err := DB.Exec(deleteBackupRecordSql, currentSelectedRow.TaskID); err != nil {
				appLog.Errorf("删除备份记录失败: %v", err)
				dialog.ShowError(fmt.Errorf("删除备份记录失败: %v", err), windows)
				return
			}

			appLog.Success("删除任务成功")
			dialog.ShowInformation("提示", "删除任务成功", windows)
			return
		} else {
			appLog.Info("取消删除任务")
			return
		}
	}, windows)
	// 显示确认对话框
	confirmDialog.Show()
}

// 编辑任务按钮
func editTaskButton(windows fyne.Window) *widget.Button {
	// 创建编辑任务按钮
	editTaskButton := widget.NewButton("编辑任务", func() {
		// 创建表单项目
		nameItem := widget.NewFormItem("任务名称", widget.NewEntry())                                 // 创建任务名称输入框
		nameItem.HintText = currentSelectedRow.TaskName                                           // 设置原始任务名称作为提示文本
		retentionCountItem := widget.NewFormItem("保留数量", widget.NewEntry())                       // 创建保留数量输入框
		retentionCountItem.HintText = fmt.Sprintf("%d", currentSelectedRow.RetentionCount)        // 设置原始保留数量作为提示文本
		isCompressedItem := widget.NewFormItem("是否压缩", widget.NewSelect([]string{"是", "否"}, nil)) // 创建是否压缩下拉框
		isCompressedItem.HintText = fmt.Sprintf("%t", currentSelectedRow.IsCompressed)            // 设置原始是否压缩作为提示文本

		// 整合表单项目
		formItems := []*widget.FormItem{
			nameItem,           // 任务名称
			retentionCountItem, // 保留数量
			isCompressedItem,   // 是否压缩
		}

		// 弹出表单对话框
		formDialog := dialog.NewForm("编辑任务", "提交", "取消", formItems, func(submitted bool) {
			if submitted {
				// 检查任务名称是否为空
				if nameItem.Widget.(*widget.Entry).Text == "" {
					dialog.ShowError(fmt.Errorf("任务名称不能为空"), windows)
					appLog.Error("任务名称不能为空")
					return
				}

				// 检查保留数量是否为空
				if retentionCountItem.Widget.(*widget.Entry).Text == "" {
					dialog.ShowError(fmt.Errorf("保留数量不能为空"), windows)
					appLog.Error("保留数量不能为空")
					return
				}

				// 检查保留数量是否为数字
				if _, err := strconv.Atoi(retentionCountItem.Widget.(*widget.Entry).Text); err != nil {
					dialog.ShowError(fmt.Errorf("保留数量必须为数字"), windows)
					appLog.Error("保留数量必须为数字")
					return
				}

				// 检查是否压缩是否为空
				if isCompressedItem.Widget.(*widget.Select).Selected == "" {
					dialog.ShowError(fmt.Errorf("是否压缩不能为空"), windows)
					appLog.Error("是否压缩不能为空")
					return
				}

				// 比较原始任务名称和新任务名称是否相同
				var taskNameNew string
				if nameItem.HintText != nameItem.Widget.(*widget.Entry).Text {
					taskNameNew = nameItem.Widget.(*widget.Entry).Text // 获取新任务名称的值
				} else {
					taskNameNew = currentSelectedRow.TaskName // 保持原始任务名称不变
				}

				// 比较原始保留数量和新保留数量是否相同
				var retentionCountNew int
				if retentionCountItem.HintText != retentionCountItem.Widget.(*widget.Entry).Text {
					retentionCountNew, _ = strconv.Atoi(retentionCountItem.Widget.(*widget.Entry).Text) // 获取新保留数量的值
				} else {
					retentionCountNew = currentSelectedRow.RetentionCount // 保持原始保留数量不变
				}

				// 比较原始是否压缩和新是否压缩是否相同
				var isCompressedNew bool
				if isCompressedItem.HintText != isCompressedItem.Widget.(*widget.Select).Selected {
					isCompressedNew = isCompressedItem.Widget.(*widget.Select).Selected == "是" // 获取新是否压缩的值
				} else {
					isCompressedNew = currentSelectedRow.IsCompressed // 保持原始是否压缩不变
				}

				// 检查任务名是否为已存在的
				querySql := "SELECT COUNT(*) FROM backup_tasks WHERE task_name = ? AND task_id != ?"
				var count int
				if err := DB.Get(&count, querySql, taskNameNew, currentSelectedRow.TaskID); err != nil {
					appLog.Errorf("查询任务名称失败: %v", err)
					dialog.ShowError(fmt.Errorf("查询任务名称失败: %v", err), windows)
					return
				}

				// 检查任务名是否已存在
				if count > 0 {
					appLog.Error("任务名已存在, 请重新输入")
					dialog.ShowError(fmt.Errorf("任务名已存在, 请重新输入"), windows)
					return
				}

				// 构造更新任务的SQL语句
				updateTaskSql := "UPDATE backup_tasks SET task_name = ?, retention_count = ?, is_compressed = ? WHERE task_id = ?"

				// 执行更新任务的SQL语句
				if _, err := DB.Exec(updateTaskSql, taskNameNew, retentionCountNew, isCompressedNew, currentSelectedRow.TaskID); err != nil {
					appLog.Errorf("更新任务失败: %v", err)
					dialog.ShowError(fmt.Errorf("更新任务失败: %v", err), windows)
					return
				} else {
					appLog.Success("更新任务成功")
					dialog.ShowInformation("提示", "更新任务成功", windows)
					return
				}
			} else {
				appLog.Info("取消编辑任务")
				return
			}
		}, windows)

		// 设置表单对话框的尺寸
		formDialog.Resize(fyne.NewSize(400, 300))

		// 显示表单对话框
		formDialog.Show()
	})

	return editTaskButton
}

// 创建备份记录表格
func createBackupTable() *widget.Table {
	// 创建一个表格用于显示备份记录
	backupTable := widget.NewTable(
		func() (int, int) { return len(taskResult), 9 },         // 设置表格的行数和列数
		func() fyne.CanvasObject { return widget.NewLabel("") }, // 设置表格的单元格内容
		updateBackTable, // 更新表格的单元格内容的回调函数
	)

	// 启用表头行
	backupTable.ShowHeaderRow = true

	// 自定义表头内容的创建
	backupTable.CreateHeader = func() fyne.CanvasObject {
		return widget.NewLabel("Header Template")
	}

	// 更新自定义表头内容
	backupTable.UpdateHeader = func(id widget.TableCellID, template fyne.CanvasObject) {
		// 根据列索引设置表头标签的文本内容
		switch id.Col {
		case 0:
			template.(*widget.Label).SetText("版本ID")
		case 1:
			template.(*widget.Label).SetText("任务ID")
		case 2:
			template.(*widget.Label).SetText("备份时间")
		case 3:
			template.(*widget.Label).SetText("任务名称")
		case 4:
			template.(*widget.Label).SetText("备份状态")
		case 5:
			template.(*widget.Label).SetText("备份文件名称")
		case 6:
			template.(*widget.Label).SetText("备份文件大小")
		case 7:
			template.(*widget.Label).SetText("备份存放路径")
		case 8:
			template.(*widget.Label).SetText("版本哈希")
		}
	}

	// 设置版本ID列的宽度
	backupTable.SetColumnWidth(0, 150)

	// 设置任务ID列的宽度
	backupTable.SetColumnWidth(1, 100)

	// 设置备份时间列的宽度
	backupTable.SetColumnWidth(2, 200)

	// 设置任务名称列的宽度
	backupTable.SetColumnWidth(3, 200)

	// 设置备份状态列的宽度
	backupTable.SetColumnWidth(4, 100)

	// 设置备份文件名称列的宽度
	backupTable.SetColumnWidth(5, 300)

	// 设置备份文件大小列的宽度
	backupTable.SetColumnWidth(6, 100)

	// 设置备份文件路径列的宽度
	backupTable.SetColumnWidth(7, 450)

	// 设置版本哈希列的宽度
	backupTable.SetColumnWidth(8, 100)

	// 设置表格鼠标点击事件
	backupTable.OnSelected = func(id widget.TableCellID) {
		// 检查是否在表头行上点击
		if id.Row == -1 {
			return
		}

		// 检查是否在有效的行上点击
		if id.Row >= len(taskResult) {
			appLog.Errorf("无效的行索引: %d", id.Row)
			return
		}

		// 获取选中的任务
		//currentSelectedBackup = BackupResult[id.Row]
	}

	return backupTable // 返回备份记录表格
}

// 更新备份记录的数据源
func updateBackData(keyword string) error {
	// 如果关键字为空，则查询所有任务
	if keyword == "" {
		// 构造查询SQL语句
		querySQL := "SELECT version_id,task_id,timestamp,task_name,backup_status,backup_file_name,backup_size,backup_path,version_hash FROM backup_records"

		// 查询数据库中的任务信息
		if err := DB.Select(&backupResult, querySQL); err != nil {
			appLog.Errorf("查询任务失败: %v", err)
			return err
		}

		return nil
	}

	// 如果关键字不为空，则查询包含关键字的任务
	querySQL := "SELECT version_id,task_id,timestamp,task_name,backup_status,backup_file_name,backup_size,backup_path,version_hash FROM backup_records WHERE task_name LIKE ?"

	// 拼接通配符
	searchPattern := fmt.Sprintf("%%%s%%", keyword)

	// 查询数据库中的任务信息
	if err := DB.Select(&backupResult, querySQL, searchPattern); err != nil {
		appLog.Errorf("查询任务失败: %v", err)
		return err
	}

	return nil
}

// 将数据源中的数据更新到表格中
func updateBackTable(tabId widget.TableCellID, cell fyne.CanvasObject) {
	// 检查行索引是否在有效范围内
	if tabId.Row >= len(taskResult) {
		cell.(*widget.Label).SetText("")
		appLog.Warnf("无效的行索引: %d", tabId.Row)
		return
	}

	// 获取单元格的标签
	label := cell.(*widget.Label)

	// 根据行和列设置标签的文本内容
	if tabId.Row < len(backupResult) {
		// 根据行索引获取对应的任务
		task := backupResult[tabId.Row]

		// 根据列索引设置标签的文本内容
		switch tabId.Col {
		case 0: // 版本ID
			label.SetText(task.VersionID)
		case 1: // 任务ID
			label.SetText(task.TaskID)
		case 2: // 备份时间
			label.SetText(task.TimeStamp)
		case 3: // 任务名称
			label.SetText(task.TaskName)
		case 4: // 备份状态
			label.SetText(fmt.Sprintf("%t", task.BackupStatus))
		case 5: // 备份文件名称
			label.SetText(task.BackupFileName)
		case 6: // 备份文件大小
			label.SetText(task.BackupSize)
		case 7: // 备份文件路径
			label.SetText(task.BackupPath)
		case 8: // 版本哈希
			label.SetText(task.VersionHash)
		default:
			label.SetText("") // 如果超出列范围，设置为空字符串
		}
	} else {
		label.SetText("") // 如果超出行范围，设置为空字符串
	}
}

// 更新复选框任务列表
func updateCheckBoxGroup(checkBoxGroup *widget.CheckGroup) {
	// 更新复选框任务列表的数据源
	checkBoxQuerySql := "SELECT task_name FROM backup_tasks"
	if err := DB.Select(&checkBoxList, checkBoxQuerySql); err != nil {
		appLog.Errorf("查询任务失败: %v", err)
	}

	// 重新设置复选框组的选项
	checkBoxGroup.Options = checkBoxList

	// 刷新复选框组
	checkBoxGroup.Refresh()
}

// 执行任务的逻辑
func executeButtonLogic(windows fyne.Window, progressBar *widget.ProgressBarInfinite) {
	// 检查存储选中的切片是否为空指针
	if selectedCheckBox == nil {
		appLog.Debugf("selectedCheckBox: %v", selectedCheckBox)
		appLog.Warn("没有选中的任务, 返回")
		dialog.ShowInformation("提示", "请选择要执行的任务", windows)
		return
	}

	// 检查是否有选中的任务
	if len(selectedCheckBox) == 0 {
		appLog.Warn("没有选中的任务, 返回")
		dialog.ShowInformation("提示", "请选择要执行的任务", windows)
		return
	}

	// 打开进度条
	progressBar.Hidden = false

	// 启动进度条
	progressBar.Start()
	defer func() {
		// 关闭进度条
		progressBar.Stop()
		progressBar.Hidden = true
	}()

	// 生成选中任务组ID
	taskGroupID := GenerateID(6)
	appLog.Debugf("taskGroupID: %v", taskGroupID)

	// 获取当前时间戳
	timestamp := time.Now().Format("2006-01-02 15:04:05")
	appLog.Debugf("timestamp: %v", timestamp)

	// 构造插入选中任务组合的SQL语句
	insertSQL := "INSERT INTO backup_groups (group_id, timestamp) VALUES (?, ?)"
	appLog.Debugf("insertSQL: %v", insertSQL)

	// 插入选中任务组合
	if _, err := DB.Exec(insertSQL, taskGroupID, timestamp); err != nil {
		appLog.Errorf("保存选中任务组合失败: %v", err)
	}

	// 存储任务ID
	var taskIDs []int

	// 根据选中的任务名获取任务ID并插入到备份任务组合表中
	for _, taskName := range selectedCheckBox {
		var taskID int
		if err := DB.Get(&taskID, "SELECT task_id FROM backup_tasks WHERE task_name = ?", taskName); err != nil {
			appLog.Errorf("查询任务ID失败: %v", err)

			// 删除插入的任务组合
			deleteSQL := "DELETE FROM backup_groups WHERE group_id =?"
			if _, err := DB.Exec(deleteSQL, taskGroupID); err != nil {
				appLog.Errorf("删除插入的任务组合失败: %v", err)
			}
			appLog.Debug("根据选中的任务名获取任务ID失败, 清除插入的任务组合")

			appLog.Warn("查询任务ID失败, 返回")
			return // 处理错误
		} else {
			// 构造插入选中任务组合的SQL语句
			insertSQL := "INSERT INTO backup_group_tasks (group_id, task_id) VALUES (?, ?)"

			// 插入选中任务组合的任务
			if _, err := DB.Exec(insertSQL, taskGroupID, taskID); err != nil {
				appLog.Errorf("保存选中任务组合的任务失败: %v", err)

				// 删除插入的任务组合
				deleteSQL := "DELETE FROM backup_groups WHERE group_id =?"
				if _, err := DB.Exec(deleteSQL, taskGroupID); err != nil {
					appLog.Errorf("删除插入的任务组合失败: %v", err)
				}
				appLog.Debug("保存选中任务组合的任务失败, 清除插入的任务组合")

				appLog.Warn("保存选中任务组合的任务失败, 返回")

				return
			}

			// 将任务ID添加到切片中
			taskIDs = append(taskIDs, taskID)
			appLog.Debugf("taskID: %v", taskID)
		}
	}

	// 执行备份任务
	var w sync.WaitGroup
	w.Add(1)
	go func() {
		defer w.Done()
		runBackupTask(windows, taskIDs)
	}()
	// 等待所有任务完成
	w.Wait()

	appLog.Debugf("执行备份任务 %s 完成", selectedCheckBox)
	dialog.ShowInformation("提示", "执行备份任务完成", windows)
}

func runBackupTask(windows fyne.Window, oldTaskIDs []int) {
	// 存储任务信息的结构体
	var tasks []BackupTask

	// 构造查询SQL语句
	oldQuerySql := "select task_id, task_name, target_directory, backup_directory, retention_count, is_compressed from backup_tasks where task_id in (?)"

	// 通过IN函数扩展查询语句
	newQuerySql, newTaskIds, err := sqlx.In(oldQuerySql, oldTaskIDs)
	if err != nil {
		appLog.Errorf("扩展sql失败: %v", err)
	}

	appLog.Debugf("查询任务SQL: %s", newQuerySql)
	appLog.Debugf("任务ID: %v", newTaskIds)

	// 查询数据库中的任务信息
	if err := DB.Select(&tasks, newQuerySql, newTaskIds...); err != nil {
		appLog.Errorf("查询任务失败: %v", err)
	}
	appLog.Debugf("查询用的sql: %s", newQuerySql)
	appLog.Debugf("查询的参数: %v", newTaskIds)
	appLog.Debugf("查询到的任务信息: %v", tasks)

	// 遍历任务列表---检查目标目录是否存在
	for _, task := range tasks {
		// 检查目标目录是否存在
		if _, err := CheckPath(task.TargetDirectory); err != nil {
			dialog.ShowError(fmt.Errorf("在检查任务[%s]的目标目录[%s]时出错: %v", task.TaskName, task.TargetDirectory, err), windows)
			appLog.Errorf("在检查任务[%s]的目标目录[%s]时出错: %v", task.TaskName, task.TargetDirectory, err)
			appLog.Debug("执行备份任务返回")
			continue
		}

		// 检查备份目录是否存在, 如果不存在则创建
		if _, err := CheckPath(task.BackupDirectory); err != nil {
			if err := os.MkdirAll(task.BackupDirectory, 0755); err != nil {
				appLog.Errorf("在创建任务[%s]的备份目录[%s]时出错: %v", task.TaskName, task.BackupDirectory, err)
				dialog.ShowError(fmt.Errorf("在创建任务[%s]的备份目录[%s]时出错: %v", task.TaskName, task.BackupDirectory, err), windows)
				appLog.Debug("执行备份任务返回")
				continue
			}
		}

		// 构建备份文件名前缀
		backupTime := time.Now().Format("20060102150405")
		backupFileNamePrefix := fmt.Sprintf("%s_%s", task.TaskName, backupTime)

		// 获取versionID
		versionID := GenerateID(6)

		// 运行备份任务
		targetDir := filepath.Dir(task.TargetDirectory)                                 // 获取目标目录的目录部分
		targetName := filepath.Base(task.TargetDirectory)                               // 获取目标目录的最后一个部分
		backupFileNamePath := filepath.Join(task.BackupDirectory, backupFileNamePrefix) // 获取构建的备份文件路径

		// 执行备份任务
		zipPath, err := CreateZipFromOSPaths(DB, targetDir, targetName, backupFileNamePath)
		if err != nil {
			errorSql := "insert into backup_records (version_id, task_id, timestamp, task_name, backup_status, backup_file_name, backup_size, backup_path, version_hash) values (?, ?, ?, ?, ?, ?, ?, ?, ?)"
			if _, err := DB.Exec(errorSql, versionID, task.TaskID, backupTime, task.TaskName, "false", "-", "-", "-", "0", "-"); err != nil {
				appLog.Errorf("插入备份记录失败: %v", err)
			}
			appLog.Errorf("执行备份任务失败: %v", err)
			continue
		}

		// 获取备份文件的后8位MD5哈希值
		backupFileMD5, err := GetFileMD5Last8(zipPath)
		if err != nil {
			errorSql := "insert into backup_records (version_id, task_id, timestamp, task_name, backup_status, backup_file_name, backup_size, backup_path, version_hash) values (?, ?, ?, ?, ?, ?, ?, ?, ?)"
			if _, err := DB.Exec(errorSql, versionID, task.TaskID, backupTime, task.TaskName, "false", "-", "-", "-", "0", "-"); err != nil {
				appLog.Errorf("插入备份记录失败: %v", err)
			}
			appLog.Errorf("获取 %s 的文件MD5失败: %v", zipPath, err)
			dialog.ShowError(fmt.Errorf("获取 %s 的文件MD5失败: %v", zipPath, err), windows)
			continue
		}

		// 获取备份文件的大小
		backupFileSize, err := HumanReadableSize(zipPath)
		if err != nil {
			errorSql := "insert into backup_records (version_id, task_id, timestamp, task_name, backup_status, backup_file_name, backup_size, backup_path, version_hash) values (?, ?, ?, ?, ?, ?, ?, ?, ?)"
			if _, err := DB.Exec(errorSql, versionID, task.TaskID, backupTime, task.TaskName, "false", "-", "-", "-", "-"); err != nil {
				appLog.Errorf("插入备份记录失败: %v", err)
			}
			appLog.Errorf("获取 %s 的文件大小失败: %v", zipPath, err)
			dialog.ShowError(fmt.Errorf("获取 %s 的文件大小失败: %v", zipPath, err), windows)
			continue
		}

		// 插入备份记录
		insertSql := "insert into backup_records (version_id, task_id, timestamp, task_name, backup_status, backup_file_name, backup_size, backup_path, version_hash) values (?, ?, ?, ?, ?, ?, ?, ?,?)"
		if _, err := DB.Exec(insertSql, versionID, task.TaskID, backupTime, task.TaskName, "true", filepath.Base(zipPath), backupFileSize, task.BackupDirectory, backupFileMD5); err != nil {
			appLog.Errorf("插入备份记录失败: %v", err)
			continue
		}

		// 获取备份目录下的以指定扩展名的文件列表
		zipFiles, err := GetZipFiles(task.BackupDirectory, ".zip")
		if err != nil {
			appLog.Errorf("获取 %s 的目录下的.zip文件失败: %v", task.BackupDirectory, err)
			continue
		}

		// 删除多余的备份文件
		if len(zipFiles) > task.RetentionCount {
			if err := RetainLatestFiles(DB, zipFiles, task.RetentionCount); err != nil {
				appLog.Errorf("在删除[%s]的备份文件时出错: %v", task.TaskName, err)
				appLog.Debug("跳过清理备份文件")
			}
		}
	}
}
